﻿#include "stdafx.h"
#include "modules.h"

#include <memory>
#include <algorithm>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/DynamicLibrary.h>

using namespace llvm;
using namespace std::experimental;

std::multimap< std::string, std::unique_ptr<llvm::Module> > _modules;
std::set<std::string> funcs;	// 被使用的函数

extern std::unique_ptr<Module> module;
extern llvm::LLVMContext llvmContext;

llvm::Function * CLangModule::getFunction(const std::string & full_name) {
	std::string packageName, name;
	auto i = full_name.find_last_of('.');
	if (i == std::string::npos) {
		packageName = "c";
		name = full_name;
	}
	else {
		packageName = full_name.substr(0, i);
		name = full_name.substr(i + 1);
	}

	auto *f = module->getFunction(name);
	if (f) return f;

	auto p = _modules.equal_range(packageName);
	if (p.first == p.second) return nullptr;
	for (auto i = p.first; i != p.second; i++ ) {
		auto x=i->second->getFunction(name);
		if (x) {	// 找到了
			auto f=x->getFunctionType();
			Function *o = Function::Create(f, Function::ExternalLinkage,	name, module.get());
			funcs.insert(name);
			return o;
		}
	}

	return nullptr;
}

void CLangModule::moveAll(llvm::ExecutionEngine * engine)
{
	//for (auto &i : _modules) {
	//	auto &v=i.second;
	//	engine->addModule(std::move(v));
	//}
	//_modules.clear();
	funcs.insert("hsurfb_at");
	funcs.insert("printf");

	for( auto name : funcs ){
		auto *addr = sys::DynamicLibrary::SearchForAddressOfSymbol(name);
		if (!addr) {
			addr = sys::DynamicLibrary::SearchForAddressOfSymbol("_"+name);
		}
		if (addr) {
//#ifdef _WIN32
//			std::string n = "_" + name;
//#else
			std::string n = name;
//#endif // 
			std::cout << "Find function " << name << " in DLL" << std::endl;
			engine->addGlobalMapping("_"+n, (uint64_t)addr);
			engine->addGlobalMapping(n, (uint64_t)addr);
		}
	}
}

void CLangModule::loadLLFile(const filesystem::path& file) {
	std::string filename = file.string();
	std::cout << "Try to load:" << file << std::endl;
	llvm::SMDiagnostic error;

	auto m = getLazyIRFileModule(filename, error, llvmContext);

	if ( std::string::npos!= filename.rfind(".ll", filename.size()-3) || std::string::npos !=filename.rfind(".bc", filename.size() - 3) )
		filename = filename.substr(0, filename.length() - 3);

	std::string dll = filename + ".dll";
	if (filesystem::exists(filesystem::path(dll))) {
		std::string err;
		if (sys::DynamicLibrary::LoadLibraryPermanently(dll.c_str(), &err)) {
			std::cerr << "读取 " + dll + " 失败：" << err << std::endl;
		}
	}

	filename = filename.substr(4);
	std::replace(filename.begin(), filename.end(), '/', '.');
	std::replace(filename.begin(), filename.end(), '\\', '.');

	auto i = filename.find_last_of('.');
	filename.erase(i, filename.size() - i);

	_modules.insert(std::make_pair(filename, std::move(m)));
}

void CLangModule::loadSiFile(const filesystem::path& file) {
	std::string name = file.string();
}

void CLangModule::shutdown()
{
	_modules.clear();
}
